﻿using Anno.EngineData;
using Anno.Rpc.Storage;
using Flurl.Http;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Swashbuckle.AspNetCore.SwaggerUI;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace Anno.GateWay
{
    public static class SwaggerStartup
    {
        static object LOCK = new object();
        static Timer timer;
        static bool polling = false;
        static int pollingInterval = 5000;

        static SwaggerUIOptions options;
        public static IServiceCollection AddAnnoSwagger(this IServiceCollection services)
        {
            services.AddSwaggerGen();
            return services;
        }
        public static void UseAnnoSwagger(this IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseSwagger();
            app.UseSwaggerUI(async it =>
            {
                //it.SwaggerEndpoint("/AnnoSwagger/annoswagger.json", "annoswagger");
                //it.SwaggerEndpoint("/AnnoSwagger/annoswagger2.json", "annoswagger2");
                it.ShowCommonExtensions();
                it.ShowExtensions();

                #region UpdateDocs
                options = it;
                //await GetServices();
                timer = new Timer(async x =>
                {
                    if (polling)
                    {
                        return;
                    }
                    lock (LOCK)
                    {
                        polling = true;
                    }

                    await UpdateDocs();

                    lock (LOCK)
                    {
                        polling = false;
                    }

                }, null, 500, pollingInterval);
                #endregion
            });
            app.UseRouting();
            //app.UseEndpoints(endpoints =>
            //{
            //    endpoints.Map("/AppWcf001/docs/swagger.json", () => { return ApiSwagger.SwaggerAnnoJson("http://localhost:5002", "AppWcf001"); });
            //    endpoints.Map("/App001/docs/swagger.json", () => { return ApiSwagger.SwaggerAnnoJson("http://localhost:5002", "App001"); });
            //});
            app.MapWhen(http =>
            {
                var path = http.Request.Path.ToString();
                return path.EndsWith("/docs/swagger.json", System.StringComparison.OrdinalIgnoreCase);
            }, MapWhenHandler);
        }
        private static void MapWhenHandler(IApplicationBuilder app)
        {
            app.Use(next => new RequestDelegate(async http =>
            {
                await Task.Run(() =>
                {
                    var path = http.Request.Path.ToString().Trim('/');
                    var serviceName = path.Split('/')[0];

                    var annoDocUrl = "http://localhost:" + Const.AppSettings.GetAppSettings<int>("ListenPort", "5000");
                    http.Response.WriteAsync(ApiSwagger.SwaggerAnnoJson(annoDocUrl, serviceName));

                    return Task.FromResult(http.Response.StatusCode);
                });
            }));
        }

        public async static Task UnUseSwagger(this object obj)
        {
            timer.Dispose();
            timer = null;
        }
        /// <summary>
        /// 动态更新服务文档
        /// </summary>
        /// <returns></returns>
        private static async Task UpdateDocs()
        {
            if (options == null) return;
            if (options.ConfigObject.Urls == null)
                options.ConfigObject.Urls = new List<UrlDescriptor>();

            var urls = new List<UrlDescriptor>();

            //Const.AppSettings.GetAppSettings<int>("ListenPort", "5000");
            //var annoDocUrl = "http://localhost:" + Const.AppSettings.GetAppSettings<int>("ListenPort", "5000");
            //var micros = $"{annoDocUrl}/AnnoApi/Anno.Plugs.Trace/Router/GetServiceInstances".WithHeader("Content-Type", "application/json")
            //    .GetAsync().ReceiveJson<ActionResult<List<ServiceInformation>>>().Result;
            var micros = Rpc.Client.Connector.Micros;
            if (micros != null && micros.Count > 0)
            {
                foreach (var micro in micros)
                {
                    var serviceName = micro.Mi.Nickname;
                    if (!urls.Any(a => a.Name.Equals(serviceName, System.StringComparison.OrdinalIgnoreCase)))
                        urls.Add(new UrlDescriptor { Url = $"/{serviceName}/docs/swagger.json", Name = serviceName });
                }
            }

            options.ConfigObject.Urls = urls;
        }

        /// <summary>
        /// 通过配置设置服务
        /// </summary>
        /// <returns></returns>
        //private static async Task GetServices()
        //{
        //    if (options == null) return;
        //    var urls = new List<UrlDescriptor>();

        //    var serviceNames = Const.AppSettings.GetAppSettings<string>("ServiceNames");

        //    if (!string.IsNullOrWhiteSpace(serviceNames))
        //    {
        //        var micros = serviceNames.Split(';');
        //        foreach (var _serviceName in micros)
        //        {
        //            var serviceName = _serviceName.Trim();
        //            if (!urls.Any(a => a.Name.Equals(serviceName, System.StringComparison.OrdinalIgnoreCase)))
        //                urls.Add(new UrlDescriptor { Url = $"/{serviceName}/docs/swagger.json", Name = serviceName });
        //        }
        //        options.ConfigObject.Urls = urls;
        //    }
        //}
    }
}
